Skip to main content

aviutl2\generic\binding/
host_app.rs

1use crate::AviUtl2Info;
2use pastey::paste;
3use std::num::NonZeroIsize;
4
5/// ホストアプリケーションのハンドル。
6/// プラグインの初期化処理で使用します。
7///
8/// # Panics
9///
10/// この型がプラグインの初期化処理の外で使用された場合はPanicします。
11pub struct HostAppHandle<'a> {
12    internal: *mut aviutl2_sys::plugin2::HOST_APP_TABLE,
13    global_leak_manager: &'a mut crate::common::LeakManager,
14    is_register_plugin_done: std::sync::Arc<std::sync::atomic::AtomicBool>,
15    plugin_registry: &'a mut crate::generic::PluginRegistry,
16    is_edit_handle_available: std::sync::Arc<std::sync::atomic::AtomicBool>,
17}
18
19/// プラグインの初期化状態を管理するためのハンドル。
20pub struct SubPlugin<T> {
21    plugin: std::marker::PhantomData<T>,
22    internal: std::sync::Arc<InternalReferenceHandle>,
23}
24struct InternalReferenceHandle {
25    uninitialize_fn: fn(),
26}
27impl Drop for InternalReferenceHandle {
28    fn drop(&mut self) {
29        (self.uninitialize_fn)();
30    }
31}
32
33impl<'plugin> HostAppHandle<'plugin> {
34    pub(crate) unsafe fn new(
35        internal: *mut aviutl2_sys::plugin2::HOST_APP_TABLE,
36        global_leak_manager: &'plugin mut crate::common::LeakManager,
37        is_register_plugin_done: std::sync::Arc<std::sync::atomic::AtomicBool>,
38        plugin_registry: &'plugin mut crate::generic::PluginRegistry,
39        is_edit_handle_available: std::sync::Arc<std::sync::atomic::AtomicBool>,
40    ) -> Self {
41        Self {
42            internal,
43            global_leak_manager,
44            is_register_plugin_done,
45            plugin_registry,
46            is_edit_handle_available,
47        }
48    }
49
50    fn assert_not_killed(&self) {
51        if self
52            .is_register_plugin_done
53            .load(std::sync::atomic::Ordering::SeqCst)
54        {
55            panic!("This HostAppHandle is no longer valid.");
56        }
57    }
58
59    /// プロジェクトデータ編集用のハンドルを登録します。
60    pub fn create_edit_handle(&mut self) -> crate::generic::EditHandle {
61        self.assert_not_killed();
62        let raw_handle = unsafe { ((*self.internal).create_edit_handle)() };
63        unsafe {
64            crate::generic::EditHandle::new(raw_handle, self.is_edit_handle_available.clone())
65        }
66    }
67
68    /// インポートメニューを登録します。
69    ///
70    /// # See Also
71    ///
72    /// - [`crate::generic::menus`]
73    pub fn register_import_menu<F>(&mut self, name: &str, callback: F)
74    where
75        F: Fn() + 'static + Send + Sync,
76    {
77        self.register_menu_internal(name, callback, unsafe {
78            (*self.internal).register_import_menu_param
79        });
80    }
81
82    /// エクスポートメニューを登録します。
83    ///
84    /// # See Also
85    ///
86    /// - [`crate::generic::menus`]
87    pub fn register_export_menu<F>(&mut self, name: &str, callback: F)
88    where
89        F: Fn() + 'static + Send + Sync,
90    {
91        self.register_menu_internal(name, callback, unsafe {
92            (*self.internal).register_export_menu_param
93        });
94    }
95
96    /// レイヤーメニューを登録します。
97    /// レイヤー編集でオブジェクト未選択時の右クリックメニューに追加されます。
98    /// 名前に`\\`を含めるとサブメニューとして登録されます。
99    ///
100    /// # See Also
101    ///
102    /// - [`crate::generic::menus`]
103    pub fn register_layer_menu<F>(&mut self, name: &str, callback: F)
104    where
105        F: Fn() + 'static + Send + Sync,
106    {
107        self.register_menu_internal(name, callback, unsafe {
108            (*self.internal).register_layer_menu_param
109        });
110    }
111
112    /// オブジェクトメニューを登録します。
113    /// レイヤー編集でオブジェクト選択時の右クリックメニューに追加されます。
114    /// 名前に`\\`を含めるとサブメニューとして登録されます。
115    ///
116    /// # See Also
117    ///
118    /// - [`crate::generic::menus`]
119    pub fn register_object_menu<F>(&mut self, name: &str, callback: F)
120    where
121        F: Fn() + 'static + Send + Sync,
122    {
123        self.register_menu_internal(name, callback, unsafe {
124            (*self.internal).register_object_menu_param
125        });
126    }
127
128    /// 編集メニューを登録します。
129    /// 名前に`\\`を含めるとサブメニューとして登録されます。
130    ///
131    /// # See Also
132    ///
133    /// - [`crate::generic::menus`]
134    pub fn register_edit_menu<F>(&mut self, name: &str, callback: F)
135    where
136        F: Fn() + 'static + Send + Sync,
137    {
138        self.register_menu_internal(name, callback, unsafe {
139            (*self.internal).register_edit_menu_param
140        });
141    }
142
143    /// 設定メニューを登録します。
144    /// 設定メニューの登録後にウィンドウクライアントを登録するとシステムメニューに「設定」が追加されます。
145    ///
146    /// # See Also
147    ///
148    /// - [`crate::generic::menus`]
149    pub fn register_config_menu(
150        &mut self,
151        name: &str,
152        callback: extern "C" fn(aviutl2_sys::plugin2::HWND, aviutl2_sys::plugin2::HINSTANCE),
153    ) {
154        self.assert_not_killed();
155        unsafe {
156            ((*self.internal).register_config_menu)(
157                self.global_leak_manager.leak_as_wide_string(name),
158                callback,
159            )
160        };
161    }
162
163    /// オブジェクト編集の設定項目メニューを登録します。
164    /// オブジェクト編集の右クリックメニューに追加されます。
165    /// 名前に`\\`を含めるとサブメニューとして登録されます。
166    /// [Self::register_object_item_and_effect_menu]と違い、これはエフェクトそのものに対してはメニューが表示されず、設定項目に対してのみメニューが表示されるようになります。
167    ///
168    /// # Arguments
169    ///
170    /// - `name`: メニューの名称。
171    /// - `callback`: メニューが選択されたときのコールバック関数。
172    ///
173    /// # Note
174    ///
175    /// `register_object_item_menu`の`allow_effect_only = false`に相当します。
176    pub fn register_object_item_menu<F>(&mut self, name: &str, callback: F)
177    where
178        F: Fn(crate::generic::ObjectHandle, &str, usize, &str) + 'static + Send + Sync,
179    {
180        self.assert_not_killed();
181        let trampoline_param: Box<F> = Box::new(callback);
182        let trampoline_param_ptr = Box::into_raw(trampoline_param);
183        let name_wide = self.global_leak_manager.leak_as_wide_string(name);
184        unsafe {
185            ((*self.internal).register_object_item_menu_param)(
186                name_wide,
187                false,
188                trampoline_param_ptr as *mut std::ffi::c_void,
189                trampoline::<F>,
190            );
191        }
192
193        unsafe extern "C" fn trampoline<F>(
194            param: *mut std::ffi::c_void,
195            object_handle: aviutl2_sys::plugin2::OBJECT_HANDLE,
196            name_and_index: aviutl2_sys::common::LPCWSTR,
197            item_name: aviutl2_sys::common::LPCWSTR,
198        ) where
199            F: Fn(crate::generic::ObjectHandle, &str, usize, &str) + 'static + Send + Sync,
200        {
201            let callback = unsafe { &mut *(param as *mut F) };
202            let object_handle = crate::generic::ObjectHandle::from(object_handle);
203            let name_and_index_str = unsafe { crate::common::load_wide_string(name_and_index) };
204            let (name_str, index) = parse_name_and_index(&name_and_index_str);
205            let item_name_str = unsafe { crate::common::load_wide_string(item_name) };
206            if let Err(panic_info) =
207                crate::utils::catch_unwind_with_panic_info(std::panic::AssertUnwindSafe(|| {
208                    callback(object_handle, name_str, index, &item_name_str);
209                }))
210            {
211                tracing::error!(
212                    "Panic occurred in object item menu callback: {}",
213                    panic_info
214                );
215                let _ = crate::logger::write_error_log(&panic_info);
216            }
217        }
218    }
219
220    /// オブジェクト編集の設定項目メニューを登録します。
221    /// オブジェクト編集の右クリックメニューに追加されます。
222    /// 名前に`\\`を含めるとサブメニューとして登録されます。
223    /// [Self::register_object_item_menu]と違い、これはエフェクトそのものに対してもメニューが表示されるようになります。
224    ///
225    /// # Arguments
226    ///
227    /// - `name`: メニューの名称。
228    /// - `callback`: メニューが選択されたときのコールバック関数。
229    ///
230    /// # Note
231    ///
232    /// `register_object_item_menu`の`allow_effect_only = true`に相当します。
233    pub fn register_object_item_and_effect_menu<F>(&mut self, name: &str, callback: F)
234    where
235        F: Fn(crate::generic::ObjectHandle, &str, usize, Option<&str>) + 'static + Send + Sync,
236    {
237        self.assert_not_killed();
238        let trampoline_param: Box<F> = Box::new(callback);
239        let trampoline_param_ptr = Box::into_raw(trampoline_param);
240        let name_wide = self.global_leak_manager.leak_as_wide_string(name);
241        unsafe {
242            ((*self.internal).register_object_item_menu_param)(
243                name_wide,
244                true,
245                trampoline_param_ptr as *mut std::ffi::c_void,
246                trampoline::<F>,
247            );
248        }
249
250        unsafe extern "C" fn trampoline<F>(
251            param: *mut std::ffi::c_void,
252            object_handle: aviutl2_sys::plugin2::OBJECT_HANDLE,
253            effect_name_and_index: aviutl2_sys::common::LPCWSTR,
254            item_name: aviutl2_sys::common::LPCWSTR,
255        ) where
256            F: Fn(crate::generic::ObjectHandle, &str, usize, Option<&str>) + 'static + Send + Sync,
257        {
258            let callback = unsafe { &mut *(param as *mut F) };
259            let object_handle = crate::generic::ObjectHandle::from(object_handle);
260            let effect_name_and_index =
261                unsafe { crate::common::load_wide_string(effect_name_and_index) };
262            let item_name = (!item_name.is_null())
263                .then(|| unsafe { crate::common::load_wide_string(item_name) });
264
265            let (effect_name_str, index) = parse_name_and_index(&effect_name_and_index);
266            let item_name_option = item_name.as_deref();
267            if let Err(panic_info) =
268                crate::utils::catch_unwind_with_panic_info(std::panic::AssertUnwindSafe(|| {
269                    callback(object_handle, effect_name_str, index, item_name_option);
270                }))
271            {
272                tracing::error!(
273                    "Panic occurred in object item menu with effect callback: {}",
274                    panic_info
275                );
276                let _ = crate::logger::write_error_log(&panic_info);
277            }
278        }
279    }
280
281    /// ファイルをドロップしたときの処理を登録します。
282    ///
283    /// # Arguments
284    ///
285    /// - `name`: ドラッグ時のツールチップや入力プラグインの設定で表示する名称。
286    /// - `file_filter`: 対応するファイルフィルタ。
287    /// - `callback`: ドロップされたファイルのパスを受け取るコールバック関数。
288    pub fn register_file_drop_handler<F>(
289        &mut self,
290        name: &str,
291        file_filters: &[crate::common::FileFilter],
292        callback: F,
293    ) where
294        F: Fn(std::path::PathBuf) + 'static + Send + Sync,
295    {
296        self.assert_not_killed();
297        let callback_box = Box::new(callback);
298        let callback_ptr = Box::into_raw(callback_box);
299        let name_wide = self.global_leak_manager.leak_as_wide_string(name);
300        let file_filter_wide = self
301            .global_leak_manager
302            .leak_as_wide_string(&crate::common::format_file_filters(file_filters));
303        unsafe {
304            ((*self.internal).register_file_drop_param_handler)(
305                name_wide,
306                file_filter_wide,
307                callback_ptr as *mut std::ffi::c_void,
308                file_drop_trampoline::<F>,
309            );
310        }
311    }
312
313    /// ウィンドウクライアントを登録します。
314    ///
315    /// # Panics
316    ///
317    /// Win32のウィンドウハンドル以外が渡された場合はPanicします。
318    pub fn register_window_client<T: raw_window_handle::HasWindowHandle>(
319        &mut self,
320        name: &str,
321        instance: &T,
322    ) -> Result<(), raw_window_handle::HandleError> {
323        self.assert_not_killed();
324        let raw_handle = instance.window_handle()?;
325        let hwnd = match raw_handle.as_raw() {
326            raw_window_handle::RawWindowHandle::Win32(handle) => handle.hwnd,
327            _ => panic!("Only Win32WindowHandle is supported"),
328        };
329        unsafe {
330            ((*self.internal).register_window_client)(
331                self.global_leak_manager.leak_as_wide_string(name),
332                hwnd.get() as *mut std::ffi::c_void,
333            );
334        }
335        Ok(())
336    }
337
338    /// メニューを一括登録します。
339    ///
340    /// # See Also
341    ///
342    /// - [`crate::generic::menus`]
343    pub fn register_menus<T: GenericPluginMenus>(&mut self) {
344        self.assert_not_killed();
345        T::register_menus(self);
346    }
347
348    /// プロジェクトファイルをロードした直後に呼ばれる関数を登録します。
349    /// また、プロジェクトの初期化時にも呼ばれます。
350    ///
351    /// # Note
352    ///
353    /// [`crate::generic::GenericPlugin::on_project_load`] が自動的に登録されるため、
354    /// 通常はこの関数を直接使用する必要はありません。
355    pub fn register_project_load_handler<F>(&mut self, callback: F)
356    where
357        F: Fn(&mut crate::generic::ProjectFile) + 'static + Send + Sync,
358    {
359        self.assert_not_killed();
360
361        type CallbackType = Box<dyn Fn(&mut crate::generic::ProjectFile) + Send + Sync>;
362        static CALLBACKS: std::sync::Mutex<Vec<CallbackType>> = std::sync::Mutex::new(Vec::new());
363
364        let callback_box = Box::new(callback);
365        let mut callbacks = CALLBACKS.lock().unwrap();
366        if callbacks.is_empty() {
367            unsafe extern "C" fn trampoline(project_file: *mut aviutl2_sys::plugin2::PROJECT_FILE) {
368                let callbacks = CALLBACKS.lock().unwrap();
369                let mut project_file =
370                    unsafe { crate::generic::ProjectFile::from_raw(project_file) };
371                for callback in callbacks.iter() {
372                    if let Err(panic_info) = crate::utils::catch_unwind_with_panic_info(
373                        std::panic::AssertUnwindSafe(|| {
374                            callback(&mut project_file);
375                        }),
376                    ) {
377                        tracing::error!("Panic occurred in project load callback: {}", panic_info);
378                        let _ = crate::logger::write_error_log(&panic_info);
379                    }
380                }
381            }
382            unsafe {
383                ((*self.internal).register_project_load_handler)(trampoline);
384            }
385        }
386
387        callbacks.push(callback_box);
388    }
389
390    /// プロジェクトファイルを保存する直前に呼ばれる関数を登録します。
391    ///
392    /// # Note
393    ///
394    /// [`crate::generic::GenericPlugin::on_project_save`] が自動的に登録されるため、
395    /// 通常はこの関数を直接使用する必要はありません。
396    pub fn register_project_save_handler<F>(&mut self, callback: F)
397    where
398        F: Fn(&mut crate::generic::ProjectFile) + 'static + Send + Sync,
399    {
400        self.assert_not_killed();
401
402        type CallbackType = Box<dyn Fn(&mut crate::generic::ProjectFile) + Send + Sync>;
403        static CALLBACKS: std::sync::Mutex<Vec<CallbackType>> = std::sync::Mutex::new(Vec::new());
404
405        let callback_box = Box::new(callback);
406        let mut callbacks = CALLBACKS.lock().unwrap();
407        if callbacks.is_empty() {
408            unsafe extern "C" fn trampoline(project_file: *mut aviutl2_sys::plugin2::PROJECT_FILE) {
409                let callbacks = CALLBACKS.lock().unwrap();
410                let mut project_file =
411                    unsafe { crate::generic::ProjectFile::from_raw(project_file) };
412                for callback in callbacks.iter() {
413                    if let Err(panic_info) = crate::utils::catch_unwind_with_panic_info(
414                        std::panic::AssertUnwindSafe(|| {
415                            callback(&mut project_file);
416                        }),
417                    ) {
418                        tracing::error!("Panic occurred in project save callback: {}", panic_info);
419                        let _ = crate::logger::write_error_log(&panic_info);
420                    }
421                }
422            }
423            unsafe {
424                ((*self.internal).register_project_save_handler)(trampoline);
425            }
426        }
427
428        callbacks.push(callback_box);
429    }
430
431    /// 「キャッシュを破棄」が呼ばれたときに呼ばれる関数を登録します。
432    ///
433    /// # Note
434    ///
435    /// [`crate::generic::GenericPlugin::on_clear_cache`] が自動的に登録されるため、
436    /// 通常はこの関数を直接使用する必要はありません。
437    pub fn register_clear_cache_handler<F>(&mut self, callback: F)
438    where
439        F: Fn(&crate::generic::EditSection) + 'static + Send + Sync,
440    {
441        self.assert_not_killed();
442
443        type CallbackType = Box<dyn Fn(&crate::generic::EditSection) + Send + Sync>;
444        static CALLBACKS: std::sync::Mutex<Vec<CallbackType>> = std::sync::Mutex::new(Vec::new());
445
446        let callback_box = Box::new(callback);
447        let mut callbacks = CALLBACKS.lock().unwrap();
448        if callbacks.is_empty() {
449            unsafe extern "C" fn trampoline(edit_section: *mut aviutl2_sys::plugin2::EDIT_SECTION) {
450                let callbacks = CALLBACKS.lock().unwrap();
451                let edit_section = unsafe { crate::generic::EditSection::from_raw(edit_section) };
452                for callback in callbacks.iter() {
453                    if let Err(panic_info) = crate::utils::catch_unwind_with_panic_info(
454                        std::panic::AssertUnwindSafe(|| {
455                            callback(&edit_section);
456                        }),
457                    ) {
458                        tracing::error!("Panic occurred in clear cache callback: {}", panic_info);
459                        let _ = crate::logger::write_error_log(&panic_info);
460                    }
461                }
462            }
463            unsafe {
464                ((*self.internal).register_clear_cache_handler)(trampoline);
465            }
466        }
467
468        callbacks.push(callback_box);
469    }
470
471    /// シーンを変更した直後に呼ばれる関数を登録します。
472    ///
473    /// # Warning
474    ///
475    /// <div class="warning">
476    ///
477    /// この関数はAviUtl2の関数変更直後に同期的に呼ばれます。
478    /// コールバック内でプラグインをロックするとデッドロックする可能性があります。
479    ///
480    /// </div>
481    ///
482    pub fn register_change_scene_handler<F>(&mut self, callback: F)
483    where
484        F: Fn(&crate::generic::EditSection) + 'static + Send + Sync,
485    {
486        self.assert_not_killed();
487
488        type CallbackType = Box<dyn Fn(&crate::generic::EditSection) + Send + Sync>;
489        static CALLBACKS: std::sync::Mutex<Vec<CallbackType>> = std::sync::Mutex::new(Vec::new());
490
491        let callback_box = Box::new(callback);
492        let mut callbacks = CALLBACKS.lock().unwrap();
493        if callbacks.is_empty() {
494            unsafe extern "C" fn trampoline(edit_section: *mut aviutl2_sys::plugin2::EDIT_SECTION) {
495                let callbacks = CALLBACKS.lock().unwrap();
496                let edit_section = unsafe { crate::generic::EditSection::from_raw(edit_section) };
497                for callback in callbacks.iter() {
498                    if let Err(panic_info) = crate::utils::catch_unwind_with_panic_info(
499                        std::panic::AssertUnwindSafe(|| {
500                            callback(&edit_section);
501                        }),
502                    ) {
503                        tracing::error!("Panic occurred in change scene callback: {}", panic_info);
504                        let _ = crate::logger::write_error_log(&panic_info);
505                    }
506                }
507            }
508            unsafe {
509                ((*self.internal).register_change_scene_handler)(trampoline);
510            }
511        }
512
513        callbacks.push(callback_box);
514    }
515
516    /// 指定のイベントのコールバック関数を登録します。
517    ///
518    /// # Note
519    ///
520    /// コールバックはイベント用スレッドから呼ばれます。
521    /// イベント処理から `call_edit_section` は利用できません。
522    pub fn register_event_listener<F>(&mut self, event_type: EventType, callback: F)
523    where
524        F: Fn() + 'static + Send + Sync,
525    {
526        self.assert_not_killed();
527        let callback_box = Box::new(callback);
528        let callback_ptr = Box::into_raw(callback_box);
529        unsafe {
530            ((*self.internal).register_event_listener)(
531                event_type.into(),
532                callback_ptr as *mut std::ffi::c_void,
533                event_listener_trampoline::<F>,
534            );
535        }
536    }
537
538    fn register_menu_internal<F>(
539        &mut self,
540        name: &str,
541        callback: F,
542        register_fn: unsafe extern "C" fn(
543            aviutl2_sys::common::LPCWSTR,
544            *mut std::ffi::c_void,
545            unsafe extern "C" fn(*mut std::ffi::c_void),
546        ),
547    ) where
548        F: Fn() + 'static + Send + Sync,
549    {
550        self.assert_not_killed();
551        let trampoline_param: Box<MenuTrampolineParam<F>> = Box::new(callback);
552        let trampoline_param_ptr = Box::into_raw(trampoline_param);
553        unsafe {
554            register_fn(
555                self.global_leak_manager.leak_as_wide_string(name),
556                trampoline_param_ptr as *mut std::ffi::c_void,
557                menu_trampoline::<F>,
558            );
559        }
560    }
561}
562
563/// イベント種別。
564#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
565pub enum EventType {
566    /// オブジェクト情報の更新。
567    UpdateObject,
568    /// 現在の編集フレームの移動。
569    ChangeEditFrame,
570    /// 現在の編集シーンの変更。
571    ChangeEditScene,
572    /// 選択されているオブジェクトの変更。
573    ChangeFocusObject,
574}
575
576impl From<EventType> for aviutl2_sys::plugin2::EVENT_TYPE {
577    fn from(value: EventType) -> Self {
578        match value {
579            EventType::UpdateObject => aviutl2_sys::plugin2::EVENT_TYPE::UPDATE_OBJECT,
580            EventType::ChangeEditFrame => aviutl2_sys::plugin2::EVENT_TYPE::CHANGE_EDIT_FRAME,
581            EventType::ChangeEditScene => aviutl2_sys::plugin2::EVENT_TYPE::CHANGE_EDIT_SCENE,
582            EventType::ChangeFocusObject => aviutl2_sys::plugin2::EVENT_TYPE::CHANGE_FOCUS_OBJECT,
583        }
584    }
585}
586
587fn parse_name_and_index(name_and_index: &str) -> (&str, usize) {
588    let Some(pos) = name_and_index.rfind(':') else {
589        return (name_and_index, 0);
590    };
591    let index_str = &name_and_index[pos + 1..];
592    if let Ok(index) = index_str.parse::<usize>() {
593        let name = &name_and_index[..pos];
594        (name, index)
595    } else {
596        (name_and_index, 0)
597    }
598}
599
600type MenuTrampolineParam<F> = F;
601
602unsafe extern "C" fn menu_trampoline<F>(param: *mut std::ffi::c_void)
603where
604    F: Fn() + 'static + Send + Sync,
605{
606    let callback = unsafe { &mut *(param as *mut MenuTrampolineParam<F>) };
607    if let Err(panic_info) =
608        crate::utils::catch_unwind_with_panic_info(std::panic::AssertUnwindSafe(callback))
609    {
610        tracing::error!("Panic occurred in menu callback: {}", panic_info);
611        let _ = crate::logger::write_error_log(&panic_info);
612    }
613}
614
615unsafe extern "C" fn file_drop_trampoline<F>(
616    param: *mut std::ffi::c_void,
617    file_path: aviutl2_sys::common::LPCWSTR,
618) where
619    F: Fn(std::path::PathBuf) + 'static + Send + Sync,
620{
621    let callback = unsafe { &mut *(param as *mut F) };
622    let path_str = unsafe { crate::common::load_wide_string(file_path) };
623    let path = std::path::PathBuf::from(path_str);
624    if let Err(panic_info) =
625        crate::utils::catch_unwind_with_panic_info(std::panic::AssertUnwindSafe(|| {
626            callback(path);
627        }))
628    {
629        tracing::error!("Panic occurred in file drop callback: {}", panic_info);
630        let _ = crate::logger::write_error_log(&panic_info);
631    }
632}
633
634unsafe extern "C" fn event_listener_trampoline<F>(param: *mut std::ffi::c_void)
635where
636    F: Fn() + 'static + Send + Sync,
637{
638    let callback = unsafe { &mut *(param as *mut F) };
639    if let Err(panic_info) =
640        crate::utils::catch_unwind_with_panic_info(std::panic::AssertUnwindSafe(callback))
641    {
642        tracing::error!("Panic occurred in event listener callback: {}", panic_info);
643        let _ = crate::logger::write_error_log(&panic_info);
644    }
645}
646
647/// 汎用プラグインのメニュー登録用トレイト。
648///
649/// <div class="warning">
650///
651/// このトレイトは [`crate::generic::menus`] マクロで自動的に実装されます。
652/// 通常は手動で実装する必要はありません。
653///
654/// </div>
655pub trait GenericPluginMenus {
656    fn register_menus(host: &mut crate::generic::HostAppHandle);
657}
658
659#[doc(inline)]
660pub use aviutl2_macros::generic_menus as menus;
661
662#[derive(Default)]
663pub(crate) struct PluginRegistry {
664    #[cfg(feature = "input")]
665    input_plugins: Vec<std::sync::Arc<InternalReferenceHandle>>,
666    #[cfg(feature = "output")]
667    output_plugins: Vec<std::sync::Arc<InternalReferenceHandle>>,
668    #[cfg(feature = "filter")]
669    filter_plugins: Vec<std::sync::Arc<InternalReferenceHandle>>,
670    #[cfg(feature = "module")]
671    script_modules: Vec<std::sync::Arc<InternalReferenceHandle>>,
672}
673impl PluginRegistry {
674    pub(crate) fn new() -> Self {
675        Self::default()
676    }
677}
678
679macro_rules! impl_plugin_registry {
680    (
681        $description:literal,
682        $feature:literal,
683        $module:ident,
684        $name:ident,
685        $register_method:ident,
686        $PluginTrait:path,
687        $SingletonTrait:path,
688        $TableType:ty
689    ) => {
690        paste! {
691            impl<T> SubPlugin<T> {
692                #[cfg(feature = $feature)]
693                #[doc = concat!($description, "の新しいインスタンスを作成します。")]
694                pub fn [<new_ $name>](info: &AviUtl2Info) -> crate::AnyResult<Self>
695                where
696                    T: $PluginTrait + $SingletonTrait + 'static
697                {
698                    crate::$module::__bridge::initialize_plugin::<T>(info.version.into())?;
699                    let internal = std::sync::Arc::new(InternalReferenceHandle {
700                        uninitialize_fn: || {
701                            unsafe {
702                                crate::$module::__bridge::uninitialize_plugin::<T>();
703                            }
704                        },
705                    });
706                    Ok(Self {
707                        plugin: std::marker::PhantomData,
708                        internal,
709                    })
710                }
711            }
712            #[cfg(feature = $feature)]
713            impl<'a> HostAppHandle<'a> {
714                #[doc = concat!($description, "を登録します。")]
715                pub fn [<register_ $name>]<T: $PluginTrait + $SingletonTrait + 'static>(
716                    &mut self,
717                    handle: &SubPlugin<T>,
718                ) {
719                    self.assert_not_killed();
720                    unsafe { ((*self.internal).$register_method)(crate::$module::__bridge::create_table_unwind::<T>()) };
721                    self.plugin_registry
722                        .[<$name s>]
723                        .push(std::sync::Arc::clone(&handle.internal));
724                }
725                #[doc = concat!("unwindなしで", $description, "を登録します。")]
726                pub fn [<register_ $name _nounwind>]<T: $PluginTrait + $SingletonTrait + 'static>(
727                    &mut self,
728                    handle: &SubPlugin<T>,
729                ) {
730                    self.assert_not_killed();
731                    unsafe { ((*self.internal).$register_method)(crate::$module::__bridge::create_table::<T>()) };
732                    self.plugin_registry
733                        .[<$name s>]
734                        .push(std::sync::Arc::clone(&handle.internal));
735                }
736            }
737        }
738    };
739}
740
741impl_plugin_registry!(
742    "入力プラグイン",
743    "input",
744    input,
745    input_plugin,
746    register_input_plugin,
747    crate::input::InputPlugin,
748    crate::input::__bridge::InputSingleton,
749    aviutl2_sys::input2::INPUT_PLUGIN_TABLE
750);
751impl_plugin_registry!(
752    "出力プラグイン",
753    "output",
754    output,
755    output_plugin,
756    register_output_plugin,
757    crate::output::OutputPlugin,
758    crate::output::__bridge::OutputSingleton,
759    aviutl2_sys::output2::OUTPUT_PLUGIN_TABLE
760);
761impl_plugin_registry!(
762    "フィルタープラグイン",
763    "filter",
764    filter,
765    filter_plugin,
766    register_filter_plugin,
767    crate::filter::FilterPlugin,
768    crate::filter::__bridge::FilterSingleton,
769    aviutl2_sys::filter2::FILTER_PLUGIN_TABLE
770);
771#[cfg(feature = "module")]
772impl<T> SubPlugin<T> {
773    /// スクリプトモジュールの新しいインスタンスを作成します。
774    pub fn new_script_module(info: &AviUtl2Info) -> crate::AnyResult<Self>
775    where
776        T: crate::module::ScriptModule + crate::module::__bridge::ScriptModuleSingleton + 'static,
777    {
778        crate::module::__bridge::initialize_plugin::<T>(info.version.into())?;
779        let internal = std::sync::Arc::new(InternalReferenceHandle {
780            uninitialize_fn: || unsafe {
781                crate::module::__bridge::uninitialize_plugin::<T>();
782            },
783        });
784        Ok(Self {
785            plugin: std::marker::PhantomData,
786            internal,
787        })
788    }
789}
790
791#[cfg(feature = "module")]
792impl<'a> HostAppHandle<'a> {
793    /// スクリプトモジュールを登録します。
794    ///
795    /// # Arguments
796    ///
797    /// - `name`: モジュール名。
798    pub fn register_script_module<
799        T: crate::module::ScriptModule + crate::module::__bridge::ScriptModuleSingleton + 'static,
800    >(
801        &mut self,
802        name: Option<&str>,
803        handle: &SubPlugin<T>,
804    ) {
805        self.assert_not_killed();
806        unsafe {
807            if let Some(name_str) = name {
808                ((*self.internal).register_script_module_name)(
809                    crate::module::__bridge::create_table_unwind::<T>(),
810                    self.global_leak_manager.leak_as_wide_string(name_str),
811                )
812            } else {
813                ((*self.internal).register_script_module)(
814                    crate::module::__bridge::create_table_unwind::<T>(),
815                )
816            }
817        };
818        self.plugin_registry
819            .script_modules
820            .push(std::sync::Arc::clone(&handle.internal));
821    }
822
823    /// unwindなしでスクリプトモジュールを登録します。
824    ///
825    /// # Arguments
826    ///
827    /// - `name`: モジュール名。
828    pub fn register_script_module_nounwind<
829        T: crate::module::ScriptModule + crate::module::__bridge::ScriptModuleSingleton + 'static,
830    >(
831        &mut self,
832        name: Option<&str>,
833        handle: &SubPlugin<T>,
834    ) {
835        self.assert_not_killed();
836        unsafe {
837            if let Some(name_str) = name {
838                ((*self.internal).register_script_module_name)(
839                    crate::module::__bridge::create_table::<T>(),
840                    self.global_leak_manager.leak_as_wide_string(name_str),
841                )
842            } else {
843                ((*self.internal).register_script_module)(
844                    crate::module::__bridge::create_table::<T>(),
845                );
846            }
847        };
848        self.plugin_registry
849            .script_modules
850            .push(std::sync::Arc::clone(&handle.internal));
851    }
852}
853
854#[doc(hidden)]
855pub unsafe fn __internal_rwh_from_raw(
856    hwnd: aviutl2_sys::plugin2::HWND,
857    hinstance: aviutl2_sys::plugin2::HINSTANCE,
858) -> raw_window_handle::Win32WindowHandle {
859    let mut handle =
860        raw_window_handle::Win32WindowHandle::new(NonZeroIsize::new(hwnd as isize).unwrap());
861    handle.hinstance = Some(NonZeroIsize::new(hinstance as isize).unwrap());
862    handle
863}